package com.quwan.component;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.qcloudsms.SmsSingleSender;
import com.github.qcloudsms.SmsSingleSenderResult;
import com.quwan.common.Check;
import com.quwan.common.ImMsgType;
import com.quwan.common.exception.ExpCode;
import com.quwan.common.exception.ResponseException;
import com.quwan.config.yml.ImConfig;
import com.quwan.config.yml.OssConfig;
import com.quwan.config.yml.WxpayConfig;
import com.quwan.constans.CacheKey;
import com.quwan.entity.TMember;
import com.quwan.mapper.TMemberMapper;
import com.quwan.utils.NumberUtils;
import com.quwan.utils.redis.Redis;
import com.tencentyun.TLSSigAPIv2;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;


/**
 * @author laozhang
 * @date 2021-09-20
 */
@Component
public class TencentComponent {
    private static final Logger log = LoggerFactory.getLogger(TencentComponent.class);
    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private TLSSigAPIv2 tlsSigAPIv2;
    @Autowired
    private ImConfig imConfig;
    @Autowired
    private WxpayConfig wxpayConfig;
    @Autowired
    private Redis redis;
    @Autowired
    private TMemberMapper memberMapper;
    @Value("${sms.appId}")
    private int smsAppId;
    @Value("${sms.appKey}")
    private String smsAppKey;
    @Value("${sms.signName}")
    private String smsSignName;
    @Value("${sms.templateCodeId}")
    private int smsTemplateCodeId;
    @Value("${sms.orderNotify}")
    private String orderNotify;
    @Autowired
    private OssConfig ossConfig;


    /**
     * @param code 授权页 获取的code
     * @return token + openId
     */
    public JSONObject oauth2(String code) {
        Check.state(StringUtils.isNotBlank(code), ExpCode.PARAMS_ILLEGAL);
        String url = wxpayConfig.getOauth2Host().replace("CODE", code);
        ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);
        if (responseEntity.getStatusCode() != HttpStatus.OK)
            throw new ResponseException(ExpCode.WX_OAUTH2_REQUEST_FAIL.getCode(), ExpCode.WX_OAUTH2_REQUEST_FAIL.getMsg());

        JSONObject result = JSONObject.parseObject(responseEntity.getBody());
        String openId = result.getString("openid");
        if (StringUtils.isBlank(openId))
            throw new ResponseException(ExpCode.WX_OAUTH2_ERR.getCode(), ExpCode.WX_OAUTH2_ERR.getMsg());
        return getWxUserInfo(result.getString("access_token"), openId);

    }

    private JSONObject getWxUserInfo(String accessToken, String openId) {
        String url = wxpayConfig.getUserInfoInterface().replace("ACCESSTOKEN", accessToken).replace("OPENID", openId);
        ResponseEntity<String> responseEntity = restTemplate.getForEntity(url, String.class);
        if (responseEntity.getStatusCode() != HttpStatus.OK)
            throw new ResponseException(ExpCode.WX_USER_INFO_REQUEST_FAIL.getCode(), ExpCode.WX_USER_INFO_REQUEST_FAIL.getMsg());

        JSONObject result = JSONObject.parseObject(responseEntity.getBody());
        String openid = result.getString("openid");
        if (StringUtils.isBlank(openid))
            throw new ResponseException(ExpCode.WX_USER_INFO_ERR.getCode(), ExpCode.WX_USER_INFO_ERR.getMsg());

        return result;
    }

    /**
     * 批量消息推送 单次最大500
     *
     * @param syncOtherMachine 是否同步消息到发送方（1-同步，2-不同步）
     * @param fromAccount      发送方用户id
     * @param toAccount        接收方用户id集合
     * @param msgType          消息对象类型
     * @param msgContent       消息内容
     */
    public String batchPushMsg(Integer syncOtherMachine, String fromAccount, List<String> toAccount, String msgType, String msgContent) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("SyncOtherMachine", syncOtherMachine);
        jsonObject.put("To_Account", toAccount);
        jsonObject.put("From_Account", fromAccount);
        jsonObject.put("MsgLifeTime", imConfig.getMsgLifeTime());
        jsonObject.put("MsgRandom", NumberUtils.randomScopeNum(9, 9999));

        List<JSONObject> msgBody = getMsgBody(msgType, msgContent);
        jsonObject.put("MsgBody", msgBody);
        String url = imConfig.getMoreMsgUrl()
                .replace("USERSIG", createUserSig(imConfig.getAdminAcc()))
                .replace("RANDOM", NumberUtils.randomByLeght(32));
        ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, jsonObject.toJSONString(), String.class);
        if (responseEntity.getStatusCode().equals(HttpStatus.OK))
            log.info("batchPushMsg Response：{}", responseEntity.getBody());
        else
            log.error("batchPushMsg https请求失败");

        return responseEntity.getBody();
    }


    /**
     * 单聊消息
     *
     * @param syncOtherMachine 是否同步消息到发送方（1-同步，2-不同步）
     * @param fromAccount      发送方用户id
     * @param toAccount        接收方用户id集合
     * @param msgType          消息对象类型
     * @param msgContent       消息内容
     */
    public Boolean singlePushMsg(Integer syncOtherMachine, String fromAccount, String nickName, String toAccount, String msgType, String msgContent) {
        //发送消息内容参数
        JSONObject sendObjParams = new JSONObject();
        sendObjParams.put("SyncOtherMachine", syncOtherMachine);
        sendObjParams.put("From_Account", fromAccount);
        sendObjParams.put("To_Account", toAccount);
        sendObjParams.put("MsgLifeTime", imConfig.getMsgLifeTime());
        sendObjParams.put("MsgRandom", NumberUtils.randomScopeNum(9, 9999));
        //透传内容
        JSONObject ext = new JSONObject();
        JSONObject entity = new JSONObject();
        entity.put("sender", fromAccount);
        entity.put("nickname", nickName);
        ext.put("entity", entity);
        //推送设备信息 AndroidInfo
        JSONObject AndroidInfo = new JSONObject();
        AndroidInfo.put("Sound", "android.mp3");
        // 推送设备信息 ApnsInfo
        JSONObject ApnsInfo = new JSONObject();
        ApnsInfo.put("Sound", "apns.mp3");
        ApnsInfo.put("BadgeMode", 1);
        ApnsInfo.put("Title", nickName);
        ApnsInfo.put("SubTitle", msgContent);
        ApnsInfo.put("Image", "https://static.dingtalk.com/media/lQLPDhrvUfZawMfNAgDNAgCwI65CfJRk0_4BtVhPHEB0AA_512_512.png_720x720q90g.jpg?bizType=im");

        //离线消息
        JSONObject offlineInfo = new JSONObject();
        offlineInfo.put("PushFlag", 0);
        offlineInfo.put("Desc", msgContent);
        offlineInfo.put("Ext", ext.toJSONString());
        offlineInfo.put("AndroidInfo", AndroidInfo);
        offlineInfo.put("ApnsInfo", ApnsInfo);
        List<JSONObject> msgBody = getMsgBody(msgType, msgContent);
        sendObjParams.put("MsgBody", msgBody);
        sendObjParams.put("OfflinePushInfo", offlineInfo);
        String url = imConfig.getSingleMsgUrl()
                .replace("USERSIG", createUserSig(imConfig.getAdminAcc()))
                .replace("RANDOM", NumberUtils.randomByLeght(32));
        log.info("params::{}", sendObjParams.toString());
        ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, sendObjParams.toJSONString(), String.class);
        if (responseEntity.getStatusCode().equals(HttpStatus.OK)) {
            JSONObject jsonObject = JSONObject.parseObject(responseEntity.getBody());
            if ("0".equals(jsonObject.getString("ErrorCode"))) {
                log.info("singlePushMsg Success");
                return true;
            } else
                log.info("singlePushMsg Response：{}", responseEntity.getBody());
        } else
            log.error("singlePushMsg https请求失败");
        return false;
    }

    public boolean importImAccount(TMember member) {
        if (member != null) {
            String url = imConfig.getImportAccInterface()
                    .replace("USERSIG", createUserSig(imConfig.getAdminAcc()))
                    .replace("RANDOM", NumberUtils.randomByLeght(32));
            JSONObject params = new JSONObject();
            params.put("UserID", member.getId() + "");
            params.put("Nick", member.getNickName());
            if (StringUtils.isNotBlank(member.getImgUrl()))
                params.put("FaceUrl",member.getImgUrl().startsWith(ossConfig.getHostname()) ?member.getImgUrl(): ossConfig.getHostname() + "/" + member.getImgUrl());
            log.info("requestParams::{}", params.toString());
            log.info("url::{}", url);
            ResponseEntity<String> resp = restTemplate.postForEntity(url, params.toJSONString(), String.class);
            if (!resp.getStatusCode().equals(HttpStatus.OK))
                throw new RuntimeException("网路请求失败");

            JSONObject res = JSONObject.parseObject(resp.getBody());
            if ("ok".equalsIgnoreCase(String.valueOf(res.get("ActionStatus"))))
                return true;
            log.error("im账号信息导入失败 mid:{},exp:{}", member.getId(), res);
        }
        return false;
    }


    /**
     * 拼接发送消息内容
     *
     * @param msgType 消息类型
     * @param content 发送消息内容
     * @return 消息内容
     */
    private List<JSONObject> getMsgBody(String msgType, String content) {
        List<JSONObject> res = new ArrayList<>();
        if (ImMsgType.text.getCode().equals(msgType)) {
            // 文本类型
            JSONObject msgBodyJson = new JSONObject();
            msgBodyJson.put("MsgType", msgType);
            JSONObject msgContentObj = new JSONObject();
            msgContentObj.put("Text", content);
            msgBodyJson.put("MsgContent", msgContentObj);
            res.add(msgBodyJson);
        }
        return res;
    }

    public String createUserSig(String mId) {
        String key = CacheKey.IM.userSig + mId;
        Object userSig = redis.get(key);
        String ret = null;
        if (userSig == null) {
            ret = tlsSigAPIv2.genSig(mId, imConfig.getExpire() * 86400);
            redis.setEx(key, ret, NumberUtils.randomScopeNum(86400, (int) (imConfig.getExpire() / 2) * 86400).longValue());
            TMember member = memberMapper.selectOne(new LambdaQueryWrapper<TMember>()
                    .select(TMember::getNickName, TMember::getImgUrl, TMember::getId)
                    .eq(TMember::getId, mId));
            if (member!=null){
                importImAccount(member);
            }

        } else
            ret = String.valueOf(userSig);
        log.info("userSig::{}", ret);
        return ret;
    }

    /**
     * 短信服务
     *
     * @param phoneNumbers
     * @param code
     * @return
     */
    public boolean sendSms(String phoneNumbers, String code) {

        try {
            SmsSingleSender sender = new SmsSingleSender(smsAppId, smsAppKey);
            String[] param = new String[]{code, "3"};
            SmsSingleSenderResult result = sender.sendWithParam("86", phoneNumbers, smsTemplateCodeId, param, smsSignName, "", "");
            if (result.result == 0) {
                return true;
            } else {
                log.error("send msm err::{}", result.toString());
                log.info("err msg::{}", result.errMsg);
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    public JSONObject getHistoryMsg(){
        String url = imConfig.getHisotryMsgInterface()
                .replace("USERSIG", createUserSig(imConfig.getAdminAcc()))
                .replace("RANDOM", NumberUtils.randomByLeght(32));
        JSONObject params = new JSONObject();
        params.put("ChatType", "C2C");
        params.put("MsgTime", "2022061109");

        ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, params.toJSONString(), String.class);
        JSONObject res = JSONObject.parseObject(responseEntity.getBody());
        return res;

    }


    public String getUnreadMsgCount(String id) {
        String url = imConfig.getUnReadUrl()
                .replace("USERSIG", createUserSig(imConfig.getAdminAcc()))
                .replace("RANDOM", NumberUtils.randomByLeght(32));
        JSONObject params = new JSONObject();
        params.put("To_Account", id);

        ResponseEntity<String> entity = restTemplate.postForEntity(url, params.toJSONString(), String.class);
        JSONObject res = JSONObject.parseObject(entity.getBody());
        return Optional.ofNullable(res.getString("AllC2CUnreadMsgNum")).orElse("0");
    }

    public boolean sendOrderSms(String phoneNumbers) {

        try {
            SmsSingleSender sender = new SmsSingleSender(smsAppId, smsAppKey);

           //SmsSingleSenderResult result = sender.sendWithParam("86", phoneNumbers, 1487763, new ArrayList<>(), smsSignName, "", "");
           SmsSingleSenderResult result = sender.send(0,"86", phoneNumbers, orderNotify,"","");
            if (result.result == 0) {
                return true;
            } else {
                log.error("send msm err::{}", result.toString());
                log.info("err msg::{}", result.errMsg);
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
        //1487763
    }
}
